package gui;

import file.MonitorHandler;
import file.SettingsDefinition;
import gui.bf3.BF3CheckBox;
import gui.bf3.BF3ComboBox;
import gui.bf3.BF3Setting;
import gui.bf3.BF3Slider;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Hashtable;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import transparent.TransparentPanel;

/**
 * This code was edited or generated using CloudGarden's Jigloo SWT/Swing GUI
 * Builder, which is free for non-commercial use. If Jigloo is being used
 * commercially (ie, by a corporation, company or business for any purpose
 * whatever) then you should purchase a license for each developer using Jigloo.
 * Please visit www.cloudgarden.com for details. Use of Jigloo implies
 * acceptance of these licensing terms. A COMMERCIAL LICENSE HAS NOT BEEN
 * PURCHASED FOR THIS MACHINE, SO JIGLOO OR THIS CODE CANNOT BE USED LEGALLY FOR
 * ANY CORPORATE OR COMMERCIAL PURPOSE.
 */
public class VideoSettingsPanel extends TransparentPanel {

	/**
	 * 
	 */
	private static final long serialVersionUID = -4817265053851048274L;
	private static final int PANEL_WIDTH = 398;
	private static final int MONITOR_PANEL_HEIGHT = 340;
	private static final int QUALITY_PANEL_HEIGHT = 570;
	private BF3ComboBox fullscreenScreen;
	private static BF3ComboBox resolution;
	private BF3CheckBox fullscreenEnabled;
	private BF3CheckBox vsync;
	private BF3Slider fieldOfView;
	private BF3CheckBox stereoscopy;
	private BF3Slider stereoConvergence;
	private BF3Slider brightness;
	private BF3Slider contrast;
	private BF3ComboBox overallGraphicsQuality;
	private BF3ComboBox textureQuality;
	private BF3ComboBox shadowQuality;
	private BF3CheckBox transparentShadows;
	private BF3CheckBox enlighten;
	private BF3ComboBox effectsQuality;
	private BF3ComboBox shaderQuality;
	private BF3ComboBox meshQuality;
	private BF3ComboBox terrainQuality;
	private BF3ComboBox undergrowthQuality;
	private BF3Slider physicsQuality;
	private BF3Slider animationQuality;
	private BF3ComboBox antiAliasingDeferred;
	private BF3ComboBox antiAliasingPost;
	private BF3CheckBox motionBlurEnabled;
	private BF3Slider motionBlur;
	private BF3ComboBox anisotropicFilter;
	private BF3ComboBox ambientOcclusion;
	
	private MonitorHandler monitorHandler;

	public VideoSettingsPanel(List<BF3Setting> settings) {
		this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));

		monitorHandler = new MonitorHandler();
		
		// Monitor Settings Panel

		JPanel monitorPanel = new TransparentPanel();
		monitorPanel.setLayout(new BoxLayout(monitorPanel, BoxLayout.Y_AXIS));
		monitorPanel.setPreferredSize(new Dimension(PANEL_WIDTH, MONITOR_PANEL_HEIGHT));
		monitorPanel.setMaximumSize(new Dimension(PANEL_WIDTH, MONITOR_PANEL_HEIGHT));
		monitorPanel.setMinimumSize(new Dimension(PANEL_WIDTH, MONITOR_PANEL_HEIGHT));
		monitorPanel.setBorder(BorderFactory.createTitledBorder("Monitor"));

		JPanel monitorSubPanel1 = new TransparentPanel(new GridLayout(4, 2, 0, 5));
		monitorPanel.add(monitorSubPanel1);
		
		monitorSubPanel1.add(new JLabel("Fullscreen Monitor"));
		fullscreenScreen = new BF3ComboBox(SettingsDefinition.FULLSCREENSCREEN, monitorHandler.getMonitors());
		fullscreenScreen.setActionCommand("fullscreenScreen");
		fullscreenScreen.addActionListener(new VideoActionListener());
		settings.add(fullscreenScreen);
		monitorSubPanel1.add(fullscreenScreen);

		monitorSubPanel1.add(new JLabel("Fullscreen Resolution"));
		String[] monitorResolutions = monitorHandler.getMonitorResolutions(fullscreenScreen.getSelectedIndex());
		SettingsDefinition[] monitorSettingsDefinitions = new SettingsDefinition[] { SettingsDefinition.RESOLUTIONWIDTH,
				SettingsDefinition.RESOLUTIONHEIGHT, SettingsDefinition.RESOLUTIONHERTZ };
		resolution = new BF3ComboBox(monitorSettingsDefinitions, monitorResolutions);
		resolution.setActionCommand("resolution");
		resolution.addActionListener(new VideoActionListener());
		settings.add(resolution);
		monitorSubPanel1.add(resolution);

		monitorSubPanel1.add(new JLabel("Enable Fullscreen"));
		fullscreenEnabled = new BF3CheckBox(SettingsDefinition.FULLSCREENENABLED);
		fullscreenEnabled.addActionListener(new VideoActionListener());
		settings.add(fullscreenEnabled);
		monitorSubPanel1.add(fullscreenEnabled);

		monitorSubPanel1.add(new JLabel("Vertical Sync"));
		vsync = new BF3CheckBox(SettingsDefinition.VSYNC);
		vsync.addActionListener(new VideoActionListener());
		settings.add(vsync);
		monitorSubPanel1.add(vsync);

		JPanel monitorSubPanel2 = new TransparentPanel(new GridLayout(1, 2, 0, 5));
		monitorPanel.add(monitorSubPanel2);
		
		monitorSubPanel2.add(new JLabel("Field of View"));
		fieldOfView = new BF3Slider(SettingsDefinition.FIELDOFVIEW, 30, 180, 70 );
		fieldOfView.addChangeListener(new VideoChangeListener());
		fieldOfView.setMinorTickSpacing(5);
		fieldOfView.setMajorTickSpacing(30);
		Hashtable<Integer, Component> fieldOfViewlabelTable = new Hashtable<Integer, Component>();
		fieldOfViewlabelTable.put( new Integer( 30 ), new JLabel("30") );
		fieldOfViewlabelTable.put( new Integer( 60 ), new JLabel("60") );
		fieldOfViewlabelTable.put( new Integer( 90 ), new JLabel("90") );
		fieldOfViewlabelTable.put( new Integer( 120 ), new JLabel("120") );
		fieldOfViewlabelTable.put( new Integer( 150 ), new JLabel("150") );
		fieldOfViewlabelTable.put( new Integer( 180 ), new JLabel("180") );
		fieldOfView.setLabelTable(fieldOfViewlabelTable);
		
		fieldOfView.addChangeListener(new VideoChangeListener());
		settings.add(fieldOfView);
		monitorSubPanel2.add(fieldOfView);

		JPanel monitorSubPanel3 = new TransparentPanel(new GridLayout(1, 2, 0, 5));
		monitorPanel.add(monitorSubPanel3);
		
		monitorSubPanel3.add(new JLabel("Enable Stereo 3D"));
		stereoscopy = new BF3CheckBox(SettingsDefinition.STEREOSCOPY);
		stereoscopy.addActionListener(new VideoActionListener());
		settings.add(stereoscopy);
		monitorSubPanel3.add(stereoscopy);

		JPanel monitorSubPanel4 = new TransparentPanel(new GridLayout(3, 2, 0, 5));
		monitorPanel.add(monitorSubPanel4);
		
		monitorSubPanel4.add(new JLabel("Stereo 3D Convergence"));
		stereoConvergence = new BF3Slider(SettingsDefinition.STEREOCONVERGENCE,0,200,100);
		stereoConvergence.addChangeListener(new VideoChangeListener());
		stereoConvergence.setMajorTickSpacing(50);
		stereoConvergence.setMinorTickSpacing(10);
		Hashtable<Integer, Component> stereoConvergencelabelTable = new Hashtable<Integer, Component>();
		stereoConvergencelabelTable.put( new Integer( 0 ), new JLabel("0") );
		stereoConvergencelabelTable.put( new Integer( 50 ), new JLabel("50") );
		stereoConvergencelabelTable.put( new Integer( 100 ), new JLabel("100") );
		stereoConvergencelabelTable.put( new Integer( 150 ), new JLabel("150") );
		stereoConvergencelabelTable.put( new Integer( 200 ), new JLabel("200") );
		stereoConvergence.setLabelTable(stereoConvergencelabelTable);
		settings.add(stereoConvergence);
		monitorSubPanel4.add(stereoConvergence);

		monitorSubPanel4.add(new JLabel("Brightness"));
		brightness = new BF3Slider(SettingsDefinition.BRIGHTNESS);
		brightness.addChangeListener(new VideoChangeListener());
		settings.add(brightness);
		monitorSubPanel4.add(brightness);

		monitorSubPanel4.add(new JLabel("Contrast"));
		contrast = new BF3Slider(SettingsDefinition.CONTRAST);
		contrast.addChangeListener(new VideoChangeListener());
		settings.add(contrast);
		monitorSubPanel4.add(contrast);

		// Quality Settings Panel
		JPanel qualityPanel = new TransparentPanel();
		qualityPanel.setLayout(new BoxLayout(qualityPanel, BoxLayout.Y_AXIS));
		qualityPanel.setPreferredSize(new Dimension(PANEL_WIDTH, QUALITY_PANEL_HEIGHT));
		qualityPanel.setMaximumSize(new Dimension(PANEL_WIDTH, QUALITY_PANEL_HEIGHT));
		qualityPanel.setMinimumSize(new Dimension(PANEL_WIDTH, QUALITY_PANEL_HEIGHT));
		qualityPanel.setBorder(BorderFactory.createTitledBorder("Quality"));

		JPanel qualitySubPanel1 = new TransparentPanel(new GridLayout(10, 2, 0, 5));
		qualityPanel.add(qualitySubPanel1);
		
		qualitySubPanel1.add(new JLabel("Overall Quality"));
		overallGraphicsQuality = new BF3ComboBox(SettingsDefinition.OVERALLGRAPHICSQUALITY, new String[] { "Auto", "Low", "Medium", "High", "Ultra",
				"Custom" });
		overallGraphicsQuality.setActionCommand("overallGraphicsQuality");
		overallGraphicsQuality.addActionListener(new VideoActionListener());
		settings.add(overallGraphicsQuality);
		qualitySubPanel1.add(overallGraphicsQuality);

		qualitySubPanel1.add(new JLabel("Texture Quality"));
		textureQuality = new BF3ComboBox(SettingsDefinition.TEXTUREQUALITY, new String[] { "Low", "Medium", "High", "Ultra" });
		textureQuality.addActionListener(new VideoActionListener());
		settings.add(textureQuality);
		qualitySubPanel1.add(textureQuality);

		qualitySubPanel1.add(new JLabel("Shadow Quality"));
		shadowQuality = new BF3ComboBox(SettingsDefinition.SHADOWQUALITY, new String[] { "Low", "Medium", "High", "Ultra" });
		shadowQuality.addActionListener(new VideoActionListener());
		settings.add(shadowQuality);
		qualitySubPanel1.add(shadowQuality);

		qualitySubPanel1.add(new JLabel("Transparent Shadows"));
		transparentShadows = new BF3CheckBox(SettingsDefinition.TRANSPARENTSHADOWS);
		transparentShadows.addActionListener(new VideoActionListener());
		settings.add(transparentShadows);
		qualitySubPanel1.add(transparentShadows);

		qualitySubPanel1.add(new JLabel("Enlighten"));
		enlighten = new BF3CheckBox(SettingsDefinition.ENLIGHTEN);
		enlighten.addActionListener(new VideoActionListener());
		settings.add(enlighten);
		qualitySubPanel1.add(enlighten);

		qualitySubPanel1.add(new JLabel("Effects Quality"));
		effectsQuality = new BF3ComboBox(SettingsDefinition.EFFECTSQUALITY, new String[] { "Low", "Medium", "High", "Ultra" });
		effectsQuality.addActionListener(new VideoActionListener());
		settings.add(effectsQuality);
		qualitySubPanel1.add(effectsQuality);

		// hardcode to 2.000000
		qualitySubPanel1.add(new JLabel("Shader Quality"));
		shaderQuality = new BF3ComboBox(SettingsDefinition.SHADERQUALITY, new String[] { "Low", "Medium", "High", "Ultra" });
		shaderQuality.addActionListener(new VideoActionListener());
		shaderQuality.setActionCommand("shaderQuality");
		settings.add(shaderQuality);
		qualitySubPanel1.add(shaderQuality);
		shaderQuality.setEnabled(false); // TODO:remove, should be editable in
											// later versions

		qualitySubPanel1.add(new JLabel("Mesh Quality"));
		meshQuality = new BF3ComboBox(SettingsDefinition.MESHQUALITY, new String[] { "Low", "Medium", "High", "Ultra" });
		meshQuality.addActionListener(new VideoActionListener());
		settings.add(meshQuality);
		qualitySubPanel1.add(meshQuality);

		qualitySubPanel1.add(new JLabel("Terrain Quality"));
		terrainQuality = new BF3ComboBox(SettingsDefinition.TERRAINQUALITY, new String[] { "Low", "Medium", "High", "Ultra" });
		terrainQuality.addActionListener(new VideoActionListener());
		settings.add(terrainQuality);
		qualitySubPanel1.add(terrainQuality);

		qualitySubPanel1.add(new JLabel("Terrain Decoration"));
		undergrowthQuality = new BF3ComboBox(SettingsDefinition.UNDERGROWTHQUALITY, new String[] { "Low", "Medium", "High", "Ultra" });
		undergrowthQuality.addActionListener(new VideoActionListener());
		settings.add(undergrowthQuality);
		qualitySubPanel1.add(undergrowthQuality);

		JPanel qualitySubPanel2 = new TransparentPanel(new GridLayout(2, 2, 0, 5));
		qualityPanel.add(qualitySubPanel2);
		
		// hardcode to 1.000000
		qualitySubPanel2.add(new JLabel("Physics Quality"));
		physicsQuality = new BF3Slider(SettingsDefinition.PHYSICSQUALITY);
		settings.add(physicsQuality);
		qualitySubPanel2.add(physicsQuality);
		physicsQuality.setEnabled(false); // TODO:remove, should be editable in
											// later versions

		// hardcode to 1.000000
		qualitySubPanel2.add(new JLabel("Animation Quality"));
		animationQuality = new BF3Slider(SettingsDefinition.ANIMATIONQUALITY);
		qualitySubPanel2.add(animationQuality);
		settings.add(animationQuality);
		animationQuality.setEnabled(false); // TODO:remove, should be editable
											// in later versions

		
		JPanel qualitySubPanel3 = new TransparentPanel(new GridLayout(3, 2, 0, 5));
		qualityPanel.add(qualitySubPanel3);
		
		qualitySubPanel3.add(new JLabel("Antialiasing Deferred"));
		antiAliasingDeferred = new BF3ComboBox(SettingsDefinition.ANTIALIASINGDEFERRED, new String[] { "Off", "2xMSAA", "4xMSAA" });
		antiAliasingDeferred.addActionListener(new VideoActionListener());
		settings.add(antiAliasingDeferred);
		qualitySubPanel3.add(antiAliasingDeferred);

		qualitySubPanel3.add(new JLabel("Antialiasing Post"));
		antiAliasingPost = new BF3ComboBox(SettingsDefinition.ANTIALIASINGPOST, new String[] { "Off", "Low", "Medium", "High" });
		antiAliasingPost.addActionListener(new VideoActionListener());
		settings.add(antiAliasingPost);
		qualitySubPanel3.add(antiAliasingPost);
		
		qualitySubPanel3.add(new JLabel("Motion Blur"));
		motionBlurEnabled = new BF3CheckBox(SettingsDefinition.MOTIONBLURENABLED);
		motionBlurEnabled.addActionListener(new VideoActionListener());
		settings.add(motionBlurEnabled);
		qualitySubPanel3.add(motionBlurEnabled);

		
		JPanel qualitySubPanel4 = new TransparentPanel(new GridLayout(1, 2, 0, 5));
		qualityPanel.add(qualitySubPanel4);
		
		// 0-100 in 5 increment (0-0.5-1)
		qualitySubPanel4.add(new JLabel("Motion Blur Amount"));
		motionBlur = new BF3Slider(SettingsDefinition.MOTIONBLUR);
		motionBlur.addChangeListener(new VideoChangeListener());
		settings.add(motionBlur);
		qualitySubPanel4.add(motionBlur);

		
		JPanel qualitySubPanel5 = new TransparentPanel(new GridLayout(2, 2, 0, 5));
		qualityPanel.add(qualitySubPanel5);
		
		// direct values 1 2 4 8 16!! (8,16 need a check)
		qualitySubPanel5.add(new JLabel("Anisotropic Filter"));
		anisotropicFilter = new BF3ComboBox(SettingsDefinition.ANISOTROPICFILTER, new String[] { "1x", "2x", "4x", "8x", "16x" });
		anisotropicFilter.addActionListener(new VideoActionListener());
		anisotropicFilter.setActionCommand("anisotropicFilter");
		settings.add(anisotropicFilter);
		qualitySubPanel5.add(anisotropicFilter);

		qualitySubPanel5.add(new JLabel("Ambient Occlusion"));
		ambientOcclusion = new BF3ComboBox(SettingsDefinition.AMBIENTOCCLUSION, new String[] { "Off", "SSAO", "HBAO" });
		ambientOcclusion.addActionListener(new VideoActionListener());
		settings.add(ambientOcclusion);
		qualitySubPanel5.add(ambientOcclusion);

		this.add(monitorPanel);
		this.add(qualityPanel);

		overallGraphicsQuality.setSelectedIndex(5);
	}

	private class VideoActionListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			String ac = e.getActionCommand();

			if (e.getSource() instanceof BF3ComboBox) {
				BF3ComboBox cb = (BF3ComboBox) e.getSource();

				if (ac.equals("overallGraphicsQuality") && cb.getSelectedIndex() < 5) {
					if(cb.getSelectedIndex() > 0){
						setPredefinedOverallGraphicsQuality(cb.getSelectedIndex()-1); //-1 because of auto
					}
					setCustomQualitySettingsEnabled(false);
				} else if (ac.equals("overallGraphicsQuality") && cb.getSelectedIndex() == 5) {
					setCustomQualitySettingsEnabled(true);
				}

				if (ac.equals("fullscreenScreen")) {
					String[] monitorResolutions = monitorHandler.getMonitorResolutions(fullscreenScreen.getSelectedIndex());
					resolution.setModel(new DefaultComboBoxModel(monitorResolutions));
				}

				if (ac.equals("resolution")) {
					if (resolution.getSelectedItem() != null) {
						String resolution = (String) cb.getSelectedItem();
						resolution = resolution.substring(0, resolution.lastIndexOf("x")) + ","
								+ resolution.substring(resolution.lastIndexOf("x") + 1, resolution.lastIndexOf("@")) + ","
								+ resolution.substring(resolution.lastIndexOf("@") + 1, resolution.lastIndexOf("H"));
						cb.setValue(resolution);
					}

				} else if(ac.equals("anisotropicFilter")){
					String value = (String) cb.getSelectedItem();
					cb.setValue(value.substring(0, value.length()-1));
				} else {
					cb.setValue(String.valueOf(cb.getSelectedIndex()));
				}

			} else if (e.getSource() instanceof BF3CheckBox) {
				BF3CheckBox cb = (BF3CheckBox) e.getSource();
				if (cb.isSelected()) {
					cb.setValue("1");
				} else {
					cb.setValue("0");
				}
			}
		}

		private void setCustomQualitySettingsEnabled(boolean enabled) {
			textureQuality.setEnabled(enabled);
			shadowQuality.setEnabled(enabled);
			transparentShadows.setEnabled(enabled);
			enlighten.setEnabled(enabled);
			effectsQuality.setEnabled(enabled);
			// shaderQuality.setEnabled(enabled);
			meshQuality.setEnabled(enabled);
			terrainQuality.setEnabled(enabled);
			undergrowthQuality.setEnabled(enabled);
			// physicsQuality.setEnabled(enabled);
			// animationQuality.setEnabled(enabled);
			antiAliasingDeferred.setEnabled(enabled);
			antiAliasingPost.setEnabled(enabled);
			motionBlurEnabled.setEnabled(enabled);
			motionBlur.setEnabled(enabled);
			anisotropicFilter.setEnabled(enabled);
			ambientOcclusion.setEnabled(enabled);
		}

		private void setPredefinedOverallGraphicsQuality(int selectedIndex) {
			textureQuality.setSelectedIndex(selectedIndex);
			shadowQuality.setSelectedIndex(selectedIndex);
			//transparentShadows.setSelected(false);
			//enlighten.setSelected(false);
			effectsQuality.setSelectedIndex(selectedIndex);
//			shaderQuality.setSelectedIndex(0);
			meshQuality.setSelectedIndex(selectedIndex);
			terrainQuality.setSelectedIndex(selectedIndex);
			undergrowthQuality.setSelectedIndex(selectedIndex);
//			physicsQuality.setValue(50);
//			animationQuality.setValue(50);
			motionBlur.setValue(50);
			if (selectedIndex == 0) { //low
				antiAliasingDeferred.setSelectedIndex(0);
				antiAliasingPost.setSelectedIndex(0);
				motionBlurEnabled.setSelected(false);
				anisotropicFilter.setSelectedIndex(1);
				ambientOcclusion.setSelectedIndex(0);
			} else if(selectedIndex == 1){ //medium
				antiAliasingDeferred.setSelectedIndex(0);
				antiAliasingPost.setSelectedIndex(1);
				motionBlurEnabled.setSelected(false);
				anisotropicFilter.setSelectedIndex(2);
				ambientOcclusion.setSelectedIndex(1);
			} else if(selectedIndex == 2){ //high
				antiAliasingDeferred.setSelectedIndex(0);
				antiAliasingPost.setSelectedIndex(2);
				motionBlurEnabled.setSelected(true);
				anisotropicFilter.setSelectedIndex(4);
				ambientOcclusion.setSelectedIndex(2);
			} else if(selectedIndex == 3){ //ultra
				antiAliasingDeferred.setSelectedIndex(2);
				antiAliasingPost.setSelectedIndex(2);
				motionBlurEnabled.setSelected(true);
				anisotropicFilter.setSelectedIndex(4);
				ambientOcclusion.setSelectedIndex(2);
			}
		}
	}
	
	/**
	 * Receives an Array of Width, Height, RefreshRate and compares these to all
	 * monitor supported resolutions then, if it found a match, it returns the
	 * item index
	 * 
	 * @param resolutionValues
	 *            - A String[] which holds the resolution that is to be compared
	 *            to the supported resolutions. The Array needs to look like
	 *            this: ["1024","768","60"]
	 * @return the item index of a supported resolution that matches the
	 *         resolution in the parameter
	 */
	public static int getIndexOfResolution(String[] resolutionValues) {
		String newCombinedResolution = resolutionValues[0] + "x" + resolutionValues[1] + "@" + resolutionValues[2] + "Hz";

		for (int i = 0; i < resolution.getItemCount(); i++) {
			String combinedResolution = resolution.getItemAt(i).toString();
			combinedResolution = combinedResolution.substring(0, combinedResolution.indexOf("Hz")+2);
			if (combinedResolution.equals(newCombinedResolution)) {
				return i;
			}
		}
		return 0;
	}

	private class VideoChangeListener implements ChangeListener {

		@Override
		public void stateChanged(ChangeEvent e) {
			if (e.getSource() instanceof BF3Slider) {
				BF3Slider sl = (BF3Slider) e.getSource();
				sl.setValue(String.valueOf(sl.getValue()));
				sl.setToolTipText(String.valueOf(sl.getValue()));
			}

		}
	}

	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		Color ppColor = new Color(16, 16, 16, 100); // r,g,b,alpha
		g.setColor(ppColor);
		g.fillRect(+2, -2, PANEL_WIDTH - 4, MONITOR_PANEL_HEIGHT + QUALITY_PANEL_HEIGHT); // x,y,width,height
	}

}
